﻿using Sustainalytics.BusinessResearchProductStates.Entities.ResearchState;
using Sustainalytics.ClientDW.Synchronization.SyncRiskRatingsData.CorporateDataLogic;
using Sustainalytics.ClientDW.Synchronization.SyncRiskRatingsData.Events;
using Sustainalytics.ClientDW.Synchronization.SyncRiskRatingsData.Helpers;
using Sustainalytics.ClientDW.Synchronization.SyncRiskRatingsData.Indexes;
using Sustainalytics.ClientDW.Synchronization.SyncRiskRatingsData.Sources;
using Sustainalytics.Synchronization.Interface;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Sustainalytics.ClientDW.Synchronization.SyncRiskRatingsData
{
    public class CoreRiskRatingsSync
    {
        private readonly HBaseQuery _hbaseQuery;
        private readonly CoreRiskRatingResearchProfileQuery _coreRiskRatingsResearchProfileQuery;
        private readonly EventsQuery _eventsQuery;
        private readonly IncidentsQuery _incidentQuery;
        private readonly SyncCommand _syncCommand;
        private readonly ILogger _logger;
        private readonly ICorporateDataProcessor _corporateDataProcessor;

        public CoreRiskRatingsSync(
            HBaseQuery hbaseQuery,
            CoreRiskRatingResearchQuery coreRiskRatingResearchQuery,
            CoreRiskRatingResearchProfileQuery coreRiskRatingResearchProfileQuery,
            EventsQuery eventsQuery,
            IncidentsQuery incidentQuery,
            SyncCommand syncCommand,
            CorporateDataProcessor corporateDataProcessor,
            ILogger logger)
        {
            _hbaseQuery = hbaseQuery;
            _syncCommand = syncCommand;
            _coreRiskRatingsResearchProfileQuery = coreRiskRatingResearchProfileQuery;
            _eventsQuery = eventsQuery;
            _incidentQuery = incidentQuery;
            _corporateDataProcessor = corporateDataProcessor;
            _logger = logger;
        }

        public async Task<int> StartAsync(bool dropCollection = true)
        {
            var stopWatch = Stopwatch.StartNew();
            var sharedCorporateDetails = _hbaseQuery.Get(CoreRiskRatingCorporateDataQuery.Get).ToDictionary(x => x.CompanyId, x => x);
            var companyIds = sharedCorporateDetails.Keys.ToList();

            var sharedRiskRatingResearchProfiles = _coreRiskRatingsResearchProfileQuery.Get(companyIds);
            var newsevents = _eventsQuery.Get(companyIds);
            var incidents = _incidentQuery.Get(companyIds);
            var mapping = await _eventsQuery.GetMapping();

            if (sharedRiskRatingResearchProfiles.Count == 0) return 0;

            _logger.Log(
                $"{sharedRiskRatingResearchProfiles.Count} core risk rating research profile for " +
                $"{new StackFrame(1).GetMethod().Name} in " +
                $"{typeof(CompanyProfileResearchState).Name} (duration {stopWatch.Elapsed}");

            var riskRatingResearchProfiles = CoreRiskRatingResearchProfileMapping.Map(sharedCorporateDetails, sharedRiskRatingResearchProfiles);
            var riskRatingIndicators = CoreRiskRatingIndicatorMapping.Map(sharedRiskRatingResearchProfiles);
            var events = RiskRatingEventsMapping.Map(newsevents, mapping);
            var sources = RiskRatingIndicatorSource.Map(riskRatingIndicators);

            await Task.WhenAll(new[]
            {
                _syncCommand.ExecuteAsync(riskRatingResearchProfiles, CoreRiskRatingResearchProfileIndexes.RecreateIndexes),
                _syncCommand.ExecuteAsync(riskRatingIndicators, CoreRiskRatingIndicatorIndexes.RecreateIndexes),
                _syncCommand.ExecuteAsync(events, RiskRatingsEventsIndexes.RecreateIndexes, dropCollection),
                _syncCommand.ExecuteAsync(incidents, RiskRatingsIncidentsIndexes.RecreateIndexes, dropCollection),
                _syncCommand.ExecuteAsync(sources, null, dropCollection),

            }).ConfigureAwait(false);

            var researchInProgressCompanyIds = sharedCorporateDetails.Keys.Where(id => sharedRiskRatingResearchProfiles.All(rp => rp.Id != id)).ToList();

            await _corporateDataProcessor.SetResearchInProgress(researchInProgressCompanyIds, true);

            return sharedRiskRatingResearchProfiles.Count;
        }

    }
}
